package com.amigo.online.common.base.service;

import com.amigo.online.common.core.service.IRedisService;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.GenericToStringSerializer;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public abstract class BaseRedisService implements IRedisService {

	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	@Qualifier("writeRedisTemplate")
	RedisTemplate redisTemplate;
	
	@Override
	public void remove(String... keys) {
		for (String key : keys) {
            remove(key);
        }
	}

	@Override
	public void removePattern(String pattern) {
		Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0) {
            redisTemplate.delete(keys);
        }

	}

	@Override
	public void remove(String key) {
		if (exists(key)) {
            redisTemplate.delete(key);
        }
		
	}

	@Override
	public boolean exists(String key) {
		return redisTemplate.hasKey(key);
	}

	@Override
	public Object get(String key) {
		ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        return operations.get(key);
	}

	@Override
	public boolean set(String key, Object value) {
		boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
	}

	@Override
	public boolean set(String key, Object value, Long expireTime) {
		boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
	}
	
	@Override
	public List<?> getList(String key) {
		ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
		return new Gson().fromJson((String) operations.get(key), List.class);
	}

	@Override
	public boolean setList(String key,List<?> list) {
		boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, new Gson().toJson(list));
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
	}

	@Override
	public boolean setList(String key, List<?> list, Long expireTime) {
		boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, new Gson().toJson(list));
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
	}

	@Override
	public boolean flushExpireTime(String key, Long expireTime) {
		boolean result = false;
        try {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Long increase(String key, String field) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        //redisTemplate.setKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        //redisTemplate.setValueSerializer(new StringRedisSerializer());
        //redisTemplate.setHashKeySerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer(Long.class));
        if (exists(key, field)) {
            return hashOps.increment(field, 1L);
        } else {
            hashOps.putIfAbsent(field, 1);
            return 1L;
        }
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Long decrease(String key, String field) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer(Long.class));
        if (exists(key, field)) {
            long count = hashOps.increment(field, -1L);
            if (count == 0) {
                deleteField(key, field);
                return 0L;
            } else {
                return count;
            }
        }
        return 0L;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public void deleteField(String key, String field) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        hashOps.delete(field);
	}

	@Override
	public void batchDeleteField(String key, String... field) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        hashOps.delete(field);
	}

	@Override
	public Set getFields(String key) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        return hashOps.keys();
	}

	@Override
	public boolean exists(String key, String field) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        return hashOps.hasKey(field);
	}

	@Override
	public Object getValueByKeyANdField(String key, String field) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer(Long.class));
        return hashOps.get(field);
	}

	@Override
	public Map<Serializable, Object> getEntries(String key) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        //redisTemplate.setHashKeySerializer(new GenericToStringSerializer(String.class));
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer(Long.class));
        return hashOps.entries();
	}

	@Override
	public void put(String key, String field, Long value) {
		BoundHashOperations hashOps = redisTemplate.boundHashOps(key);
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer(Long.class));
        hashOps.put(field, value);
	}

}
